#include "Texture.h"

using namespace GalliumEngine;

Texture::Texture()
{
	mipMapsGenerated = false;
}

void Texture::createFromData(BYTE* data, int _width, int _height, int _bitsPerPixel, GLenum format, bool generateMipMaps)
{
	glGenTextures(1, &textureId);
	glBindTexture(GL_TEXTURE_2D, textureId);

	if(format == GL_RGB || format == GL_BGR)
	{
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _width, _height, 0, format, GL_UNSIGNED_BYTE, data);
		if(generateMipMaps)
		{
			glGenerateMipmap(GL_TEXTURE_2D);
		}
	}
	else
	{
		glTexImage2D(GL_TEXTURE_2D, 0, format, _width, _height, 0, format, GL_UNSIGNED_BYTE, data);
		if(generateMipMaps)
		{
			glGenerateMipmap(GL_TEXTURE_2D);
		}
	}

	glGenSamplers(1, &samplerId);

	file = "";
	mipMapsGenerated = generateMipMaps;
	width = _width;
	height = _height;
	bitsPerPixel = _bitsPerPixel;
}

bool Texture::loadTexture(std::string _file, bool generateMipmaps)
{
	FREE_IMAGE_FORMAT fifmt = FreeImage_GetFileType(_file.c_str(), 0);
	FIBITMAP *dib = FreeImage_Load(fifmt, _file.c_str(),0);
    dib = FreeImage_ConvertTo24Bits(dib);
	
    if( dib != NULL )
	{
        glGenTextures(1, &textureId);
		glBindTexture(GL_TEXTURE_2D, textureId);

		BYTE *bits = new BYTE[FreeImage_GetWidth(dib) * FreeImage_GetHeight(dib) * 3];

		BYTE *pixels = (BYTE*)FreeImage_GetBits(dib);

		for(int pix=0; pix<FreeImage_GetWidth(dib) * FreeImage_GetHeight(dib); pix++)
		{
			bits[pix*3+0]=pixels[pix*3+2];
			bits[pix*3+1]=pixels[pix*3+1];
			bits[pix*3+2]=pixels[pix*3+0];

		}
	     
		glTexImage2D( GL_TEXTURE_2D, 0, 3, FreeImage_GetWidth(dib), FreeImage_GetHeight(dib), 0,
				GL_RGB, GL_UNSIGNED_BYTE, bits );

		if(generateMipmaps)
		{
			glGenerateMipmap(GL_TEXTURE_2D);
		}

		glGenSamplers(1, &samplerId);
		
		FreeImage_Unload(dib);
		delete bits;

		setFiltering(TextureFiltering::TEXTURE_FILTER_MAG_BILINEAR, TextureFiltering::TEXTURE_FILTER_MIN_BILINEAR);
		setSamplerParameter(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		setSamplerParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

		return true;
	}

	return false;
}

void Texture::setFiltering(TextureFiltering::_TextureFiltering _tfMagnification, TextureFiltering::_TextureFiltering _tfMinification)
{
	if(_tfMagnification == TextureFiltering::TEXTURE_FILTER_MAG_NEAREST)
	{
		glSamplerParameteri(samplerId, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	}
	else if(_tfMagnification == TextureFiltering::TEXTURE_FILTER_MAG_BILINEAR)
	{
		glSamplerParameteri(samplerId, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}

	if(_tfMinification == TextureFiltering::TEXTURE_FILTER_MIN_NEAREST)
	{
		glSamplerParameteri(samplerId, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	}
	else if(_tfMinification == TextureFiltering::TEXTURE_FILTER_MIN_BILINEAR)
	{
		glSamplerParameteri(samplerId, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	}
	else if(_tfMinification == TextureFiltering::TEXTURE_FILTER_MIN_NEAREST_MIPMAP)
	{
		glSamplerParameteri(samplerId, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
	}
	else if(_tfMinification == TextureFiltering::TEXTURE_FILTER_MIN_BILINEAR_MIPMAP)
	{
		glSamplerParameteri(samplerId, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
	}
	else if(_tfMinification == TextureFiltering::TEXTURE_FILTER_MIN_TRILINEAR)
	{
		glSamplerParameteri(samplerId, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
	}

	tfMinification = _tfMinification;
	tfMagnification = _tfMagnification;
}

void Texture::setSamplerParameter(GLenum parameter, GLenum value)
{
	glSamplerParameteri(samplerId, parameter, value);
}

void Texture::bindTexture()
{
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, textureId);
	glBindSampler(0, samplerId);
	//glUniform1i(shaderParam, shaderValue);
}

void Texture::bindTexture(int textureUnit)
{
	glActiveTexture(GL_TEXTURE0+textureUnit);
	glBindTexture(GL_TEXTURE_2D, textureId);
	glBindSampler(textureUnit, samplerId);
	//glUniform1i(shaderParam, shaderValue);
}

void Texture::releaseTexture()
{
	glDeleteSamplers(1, &samplerId);
	glDeleteTextures(1, &textureId);
}

int Texture::getMinificationFilter()
{
	return tfMinification;
}

int Texture::getMagnificationFilter()
{
	return tfMagnification;
}

GLuint Texture::getTextureId()
{
	return textureId;
}

int Texture::getWidth()
{
	return width;
}

int Texture::getHeight()
{
	return height;
}

int Texture::getBPP()
{
	return bitsPerPixel;
}